/**
* @file server_net.h
* @brief 服务器网络基类
*/
#ifndef WH_SERVER_NET_H_
#define WH_SERVER_NET_H_

#include <fcntl.h>
#include <string.h>
#include <errno.h>

#include "net_event_manager.h"
#include "channel_base.h"
#include "retcodes.h"

#ifdef _MSC_VER
#include "winsocket.h"
#include "WinSock2.h"
#else
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#endif

namespace common
{
namespace net
{

#define LISTEN_BACKLOG (128)

/**
* @brief 服务端基类
*/
#ifdef _MSC_VER
#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#endif
	template<typename TChannel>
	class CServerNet : public INetEventHandler
	{
	public:
		typedef HashMap<int, TChannel*> TChannelMap;

		/**
		* @brief 构造函数
		*/
		CServerNet()
		{
			listen_fd_ = -1;
			send_buffer_size_ = 0;
			receive_buffer_size_ = 0;
		}

		/**
		* @brief 析构函数
		*/
		virtual ~CServerNet() { }

		int32_t Initialize(uint32_t receive_buffer_capacity, uint32_t send_buffer_capacity)
		{
			receive_buffer_size_ = receive_buffer_capacity;
			send_buffer_size_ = send_buffer_capacity;
			return ::common::SUCCEED;
		}

		int32_t Finalize()
		{
			for (typename TChannelMap::iterator iter = channel_map_.begin(); iter != channel_map_.end(); ++iter)
			{
				CChannelBase* channel = iter->second;
				if (NULL != channel)
				{
					delete channel;
				}
			}
			channel_map_.clear();
			return ::common::SUCCEED;
		}

		/**
		* @brief 启动服务端
		*
		* @param port 端口
		*
		* @return 返回启动结果
		*/
		int32_t Startup(uint16_t port)
		{
			bool ret = server_socket_.OnStart(port, LISTEN_BACKLOG, NonBlockingSocket);
			if ( !ret )
			{
				LOG_ERROR("default", "start server_net err !");
				return ESERVER_CREATE_SOCKET_FAIL;
			}
			listen_fd_ = server_socket_.GetListenFD();
			int32_t retcode = CNetEventManager::GetInstance().RegisterNetEvent(&server_socket_, 1, this);
			return retcode;
		}

		/**
		* @brief 关闭服务端
		*
		* @return 返回关闭结果
		*/
		int32_t Shutdown()
		{
			int32_t retcode = CNetEventManager::GetInstance().UnregisterNetEvent(listen_fd_);
			if (retcode != ::common::SUCCEED)
			{
				return retcode;
			}
			server_socket_.Close();
			listen_fd_ = -1;
			return ::common::SUCCEED;
		}

		/**
		* @brief 处理网络事件
		*
		* @param events 事件
		*/
		virtual void OnNetEvent(int fd, uint32_t events)
		{
			if (fd == listen_fd_)
			{
				sockaddr_in addr;
				int len = sizeof(addr);
				Socket* socket = server_socket_.Accept(addr, len);
				if ( socket == NULL )
				{
					LOG_ERROR("default", "err");
					return;
				}
				int32_t accept_fd = socket->GetListenFD();
				TChannel* channel = new TChannel();
				if (NULL == channel)
				{
					socket->Close();
					return;
				}
				channel->set_fd(accept_fd);
				std::string tip = inet_ntoa(addr.sin_addr);
				channel->set_ip(tip);
				channel->set_port(ntohs(addr.sin_port));
				channel->Initialize(receive_buffer_size_, send_buffer_size_);
				int32_t retcode = CNetEventManager::GetInstance().RegisterNetEvent(socket, 1, this);
				if (retcode != ::common::SUCCEED)
				{
					socket->Close();
					delete channel;
					LOG_WARN("default", "add net event failed");
					return;
				}
				channel->OnConnect();
				channel_map_[accept_fd] = channel;
			}
			else
			{
				TChannel* channel = GetChannel(fd);
				if (NULL == channel)
				{
					LOG_WARN("default", "channel %d not found", fd);
					return;
				}
				CRingStreams& receive_buffer = channel->receive_buffer();
				int received = ::recv(fd, (char*)receive_buffer.WriteBuffer(), receive_buffer.FreeSize(), 0);
				if (received > 0)
				{
					receive_buffer.AddWriteBufSize(received);
					channel->OnMsgEvent();
				}
				else if (received == 0 || errno != EWOULDBLOCK)
				{
					CloseChannel(fd);
				}
			}
		}

		TChannel* GetChannel(int fd)
		{
			typename TChannelMap::iterator iter = channel_map_.find(fd);
			if (iter != channel_map_.end())
			{
				return iter->second;
			}
			return NULL;
		}

		TChannel* GetFirstChannel()
		{
			typename TChannelMap::iterator iter = channel_map_.begin();
			if (iter != channel_map_.end())
			{
				return iter->second;
			}
			return NULL;
		}

		int32_t CloseChannel(int fd)
		{
			TChannel* channel = GetChannel(fd);
			if (NULL == channel)
			{
				return ESERVER_NOCHANNEL;
			}
			channel->OnDisconnect();
			channel->Finalize();
			//关闭channel;
			delete channel;
			channel = NULL;
			channel_map_.erase(fd);
			CNetEventManager::GetInstance().UnregisterNetEvent(fd);
			closesocket(fd);
			return ::common::SUCCEED;
		}

		const TChannelMap& channel_map() const
		{
			return channel_map_;
		}

	protected:
		int listen_fd_;/**<监听socket  */
		int32_t send_buffer_size_;/**<发送缓存  */
		int32_t receive_buffer_size_;/**<接收缓存  */
		TChannelMap channel_map_;
		SocketServer server_socket_;
	};
#else
template<typename TChannel>
class CServerNet : public INetEventHandler
{
public:
    typedef HashMap<int, TChannel*> TChannelMap;

    /**
    * @brief 构造函数
    */
	CServerNet()
    {
        listen_fd_ = -1;
        send_buffer_size_ = 0;
        receive_buffer_size_ = 0;
    }

    /**
    * @brief 析构函数
    */
    virtual ~CServerNet() { }

    int32_t Initialize(uint32_t receive_buffer_capacity, uint32_t send_buffer_capacity)
    {
        receive_buffer_size_ = receive_buffer_capacity;
        send_buffer_size_ = send_buffer_capacity;
        return ::common::SUCCEED;
    }

    int32_t Finalize()
    {
        for (typename TChannelMap::iterator iter = channel_map_.begin(); iter != channel_map_.end(); ++iter)
        {
            CChannelBase* channel = iter->second;
            if (NULL != channel)
            {
                delete channel;
            }
        }
        channel_map_.clear();
        return ::common::SUCCEED;
    }

    /**
    * @brief 启动服务端
    *
    * @param port 端口
    *
    * @return 返回启动结果
    */
    int32_t Startup(uint16_t port)
    {
        if (listen_fd_ != -1)
        {
            return ESERVER_ALREADY_STARTED;
        }
        listen_fd_ = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (listen_fd_ == -1)
        {
            return ESERVER_CREATE_SOCKET_FAIL;
        }
        //设置重用地址;
        int reuseaddr = 1;
        if (setsockopt(listen_fd_, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)) != 0)
        {
            return ESERVER_REUSE_ADDR_FAIL;
        }
        //关闭negle算法
        int nodelay = 1;
        if (setsockopt(listen_fd_, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay)) != 0)
        {
            return ESERVER_NODELAY_FAIL;
        }
        //设置非阻塞
        int flags = fcntl(listen_fd_, F_GETFL, 0);
        if (fcntl(listen_fd_, F_SETFL, flags |= O_NONBLOCK) != 0)
        {
            return ESERVER_NONBLOCK_FAIL;
        }
        //设置发送缓存;
        if (setsockopt(listen_fd_, SOL_SOCKET, SO_SNDBUF, (char*)(&send_buffer_size_), (socklen_t)(sizeof(send_buffer_size_))) != 0)
        {
            return ESERVER_SET_SNDBUF_FAIL;
        }
        //设置接收缓存
        if (setsockopt(listen_fd_, SOL_SOCKET, SO_RCVBUF, (char*)(&receive_buffer_size_), (socklen_t)(sizeof(receive_buffer_size_))) != 0)
        {
            return ESERVER_SET_RCVBUF_FAIL;
        }
        sockaddr_in addr;
        memset(&addr, 0, sizeof(sockaddr_in));
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
        addr.sin_port = htons(port);
        if (bind(listen_fd_, (sockaddr*)(&addr), sizeof(sockaddr_in)) != 0)
        {
            return ESERVER_BIND_FAIL;
        }
        if (listen(listen_fd_, LISTEN_BACKLOG) != 0)
        {
            return ESERVER_LISTEN_FAIL;
        }
        int32_t retcode = CNetEventManager::GetInstance().RegisterNetEvent(listen_fd_, EPOLLIN | EPOLLHUP | EPOLLERR, this);
        return retcode;
    }

    /**
    * @brief 关闭服务端
    *
    * @return 返回关闭结果
    */
    int32_t Shutdown()
    {
        int32_t retcode = CNetEventManager::GetInstance().UnregisterNetEvent(listen_fd_);
        if (retcode != ::common::SUCCEED)
        {
            return retcode;
        }
        close(listen_fd_);
        listen_fd_ = -1;
        return ::common::SUCCEED;
    }

    /**
    * @brief 处理网络事件
    *
    * @param events 事件
    */
    virtual void OnNetEvent(int fd, uint32_t events)
    {
        if (fd == listen_fd_)
        {
            sockaddr_in addr;
            socklen_t len = sizeof(addr);
            int accept_fd = accept(listen_fd_, (sockaddr*)&addr, &len);
            if (accept_fd == -1)
            {
                LOG_WARN("default", "accept failed errno %d( %s )", errno, strerror(errno));
                return;
            }
            int flags = fcntl(accept_fd, F_GETFL, 0);
            if (fcntl(accept_fd, F_SETFL, flags |= O_NONBLOCK) != 0)
            {
                close(fd);
                LOG_WARN("default", "set noblock failed");
                return;
            }
            TChannel* channel = new TChannel();
            if (NULL == channel)
            {
                close(fd);
                return;
            }
            channel->set_fd(accept_fd);
            channel->set_ip(inet_ntoa(addr.sin_addr));
            channel->set_port(ntohs(addr.sin_port));
            channel->Initialize(receive_buffer_size_, send_buffer_size_);
            int32_t retcode = CNetEventManager::GetInstance().RegisterNetEvent(accept_fd, EPOLLIN | EPOLLHUP | EPOLLERR, this);
            if (retcode != ::common::SUCCEED)
            {
                close(fd);
                delete channel;
                LOG_WARN("default", "add net event failed");
                return;
            }
            channel->OnConnect();
            channel_map_[ accept_fd ] = channel;
        }
        else
        {
            TChannel* channel = GetChannel(fd);
            if (NULL == channel)
            {
                LOG_WARN("default", "channel %d not found", fd);
                return;
            }
            CRingStreams& receive_buffer = channel->receive_buffer();
            int received = ::recv(fd, receive_buffer.WriteBuffer(), receive_buffer.FreeSize(), 0);
            if (received > 0)
            {
                receive_buffer.AddWriteBufSize(received);
                channel->OnMsgEvent();
            }
            else if (received == 0 || errno != EWOULDBLOCK)
            {
                CloseChannel(fd);
            }
        }
    }

    TChannel* GetChannel(int fd)
    {
        typename TChannelMap::iterator iter = channel_map_.find(fd);
        if (iter != channel_map_.end())
        {
            return iter->second;
        }
        return NULL;
    }

    int32_t CloseChannel(int fd)
    {
        TChannel* channel = GetChannel(fd);
        if (NULL == channel)
        {
            return ESERVER_NOCHANNEL;
        }
        channel->OnDisconnect();
        channel->Finalize();
        //关闭channel;
        delete channel;
        channel = NULL;
        channel_map_.erase(fd);
        close(fd);
        CNetEventManager::GetInstance().UnregisterNetEvent(fd);
        return ::common::SUCCEED;
    }

    const TChannelMap& channel_map() const
    {
        return channel_map_;
    }

protected:
    int listen_fd_;/**<监听socket  */
    int32_t send_buffer_size_;/**<发送缓存  */
    int32_t receive_buffer_size_;/**<接收缓存  */
    TChannelMap channel_map_;
};
#endif

}
}

#endif


